package idv.sais.ezcin;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class EZCore {
	private static final int DBDOWNLOAD_NOTIFICATION = 0x1127;
	private static final String DATABASE_DIR = "/sdcard/ezcin";
	private static final String DATABASE_LOCAL = "/sdcard/ezcin/ezcin.db";

	Context ctx;
	private StringBuilder mBuffer = new StringBuilder();
	private StringBuilder mDispBuffer = new StringBuilder();

	public static final int CANDIDATES_PER_PAGE = 6;
	private static final int CANDIDATES_DEFAULT_FONT_SIZE = 30;
	private SQLiteDatabase mDic;
	private int mCurrentPage = 0;
	private int mTotalPages = 0;
	private ArrayList<String> mCandidates;
	ArrayList<Button> mCandidateButtons;

	private HashMap<String, String> mRadical = new HashMap<String, String>();
	private HashMap<String, String> mPhonetic = new HashMap<String, String>();
	private static final String translate_ez = "w`wswkh;8jegcdfb7bab[3[2[v4u65,y,.,]n]0]ztz=zr9poqml1-/'x'i'";
	private static final String punc_ez = "的？。！，";
	private static final String translate_bpmf = "1qaz12wsx2edceerfrvr5tgb5yhnyyujmuu8i8k,9ol.90p;/-66347";
	private static final String translate_eng = "ABCDEFGHIJKLMNOPQRSTUVWXY0123456789uvwxypqrstklmnofghijabcde";
	private static final String punc_eng = ",?.!'";
	private static final String translate_sym = "     @#   +-*/^$    & > <:;) (| ] [~`} {/\\.  \"\'~?,          ";

	public EZCore(Context ctx, ArrayList<Button> candidate_buttons) {
		this.ctx = ctx;
		this.mCandidateButtons = candidate_buttons;

		if (!new File(DATABASE_DIR).exists()) {
			new File(DATABASE_DIR).mkdir();
		}
		
		if (!new File(DATABASE_LOCAL).exists()) {
			final NotificationManager nm = (NotificationManager) ctx
					.getSystemService("notification");
			Notification n = new Notification(R.drawable.icon, ctx
					.getString(R.string.downloading), System
					.currentTimeMillis());
			PendingIntent contentIntent = PendingIntent.getActivity(ctx, 0,
					new Intent(ctx, ezcin.class), 0);
			n.flags = Notification.FLAG_NO_CLEAR;
			n.setLatestEventInfo(ctx, ctx.getString(R.string.app_cname), ctx
					.getString(R.string.downloading), contentIntent);
			nm.notify(DBDOWNLOAD_NOTIFICATION, n);

			try {
				BufferedInputStream in = new BufferedInputStream(ctx
						.getResources().openRawResource(R.raw.ezcin), 8192);
				BufferedOutputStream out = new BufferedOutputStream(
						new FileOutputStream(DATABASE_LOCAL), 8192);
				int c;
				while ((c = in.read()) > -1) {
					out.write(c);
				}
				in.close();
				out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			nm.cancel(DBDOWNLOAD_NOTIFICATION);
		}

		mDic = SQLiteDatabase.openDatabase(DATABASE_LOCAL, null,
				SQLiteDatabase.OPEN_READONLY);
		mDic.setLocale(Locale.TRADITIONAL_CHINESE);

		initRadicals();
		initPhonetics();
	}

	private void initRadicals() {
		for (int i = 0; i < translate_ez.length(); ++i) {
			String raw = translate_ez.substring(i, i + 1);
			Cursor csr = mDic.rawQuery(
					"Select val from ez_radical where key =\"" + raw + "\"",
					null);
			csr.moveToFirst();
			String radical = csr.getString(csr.getColumnIndex("val"));
			csr.close();
			mRadical.put(raw, radical);
		}
	}

	private void initPhonetics() {
		for (int i = 0; i < translate_bpmf.length(); ++i) {
			String raw = translate_bpmf.substring(i, i + 1);
			Cursor csr = mDic.rawQuery(
					"Select val from bpmf_phonetic where key =\"" + raw + "\"",
					null);
			ezcin.gInstance.updateKeyboard("EZ");
			csr.moveToFirst();
			String phonetic = csr.getString(csr.getColumnIndex("val"));
			csr.close();
			mPhonetic.put(raw, phonetic);
		}
	}

	private static final int SK_PUNC = 60;
	private static final int SK_SPACE = 65;
	private static final int SK_BS = 70;
	private static final int SK_BPMF_PITCH = 50;

	public void handleKeyClick(int touchKeyCode) {

		int maxlength = 60;
		switch (ezcin.gKeyboardType) {
		case EZ:
			maxlength = translate_ez.length();
			break;
		case BPMF:
			maxlength = translate_bpmf.length() - 5;
			break;
		}
		if (touchKeyCode >= maxlength) {
			switch (touchKeyCode) {
			case SK_PUNC:
			case SK_PUNC + 1:
			case SK_PUNC + 2:
			case SK_PUNC + 3:
			case SK_PUNC + 4:
				handlePunctuation(touchKeyCode - SK_PUNC);
				break;
			case SK_SPACE:
			case SK_SPACE + 1:
			case SK_SPACE + 2:
			case SK_SPACE + 3:
			case SK_SPACE + 4:
				handleSpaceKey(touchKeyCode - SK_SPACE);
				break;
			case SK_BS:
				handleBackSpaceKey();
				break;
			case SK_BS + 1:
			case SK_BS + 2:
			case SK_BS + 3:
			case SK_BS + 4:
				changeKeyboard(touchKeyCode - SK_BS - 1);
				break;
			case SK_BPMF_PITCH:
			case SK_BPMF_PITCH + 1:
			case SK_BPMF_PITCH + 2:
			case SK_BPMF_PITCH + 3:
			case SK_BPMF_PITCH + 4:
				handleBPMFPitch(touchKeyCode);
				break;
			}
		} else {
			switch (ezcin.gKeyboardType) {
			case EZ:
				appendBuffer(translate_ez, mRadical, touchKeyCode);
				break;
			case BPMF:
				appendBuffer(translate_bpmf, mPhonetic, touchKeyCode);
				break;
			case ENG:
				insertWord(translate_eng.substring(touchKeyCode,
						touchKeyCode + 1));
				break;
			case SYM:
				insertWord(translate_sym.substring(touchKeyCode,
						touchKeyCode + 1));
				break;
			}
		}

	}

	public void handleSelection(int index) {
		insertWord(mCandidates.get(mCurrentPage * CANDIDATES_PER_PAGE + index));
		clearBuffer();
		hideSelectionButtons();
	}

	private void handlePunctuation(int index) {
		String punc = "";
		switch (ezcin.gKeyboardType) {
		case EZ:
		case BPMF:
			punc += punc_ez.charAt(index);
			break;
		case ENG:
			punc += punc_eng.charAt(index);
			break;
		}
		insertWord(punc);
	}

	private void handleSpaceKey(int index) {
		switch (index) {
		case 1:
			if (isChoosingCandidates()) {
				mCurrentPage--;
				if (mCurrentPage < 0) {
					mCurrentPage = mTotalPages - 1;
				}
				for (Button b : mCandidateButtons) {
					b.setVisibility(View.GONE);
				}
				renderCandidates();
				break;
			}
			if (ezcin.gKeyboardType == InputMode.ENG) {
				insertWord("Z");
				return;
			}
		case 3:
			if (ezcin.gKeyboardType == InputMode.ENG) {
				insertWord("z");
				return;
			}
		case 0:
			if (isChoosingCandidates()) {
				mCurrentPage++;
				if (mCurrentPage >= mTotalPages) {
					mCurrentPage = 0;
				}
				for (Button b : mCandidateButtons) {
					b.setVisibility(View.GONE);
				}
				renderCandidates();
				break;
			}
		default:
			if (mBuffer.length() == 0) {
				insertWord(" ");
				return;
			}
			queryWords();
		}
	}

	private void handleBackSpaceKey() {
		if (mBuffer.length() == 0) {
			if (ezcin.gText.length() > 0) {
				int target = ezcin.gText.getSelectionStart() == 0 ? 0
						: ezcin.gText.getSelectionStart() - 1;
				CharSequence left = ezcin.gText.getText()
						.subSequence(0, target);
				CharSequence right = ezcin.gText.getText().subSequence(
						target + 1, ezcin.gText.length());
				ezcin.gText.setText(left.toString() + right.toString());
				ezcin.gText.setSelection(target);
			}
		} else {
			if (isChoosingCandidates()) {
				clearBuffer();
				hideSelectionButtons();
			} else {
				mBuffer.delete(mBuffer.length() - 1, mBuffer.length());
				mDispBuffer.delete(mDispBuffer.length() - 1, mDispBuffer
						.length());
				ezcin.setBufferText(mDispBuffer.toString());
			}
		}
	}

	private void handleBPMFPitch(int index) {
		Log.v("index", "" + index);
		if (index >= SK_BPMF_PITCH + 1 && index <= SK_BPMF_PITCH + 4) {
			appendBuffer(translate_bpmf, mPhonetic, index);
		}
		queryWords();
	}

	private void queryWords() {
		String table;
		switch (ezcin.gKeyboardType) {
		case EZ:
			table = "ez";
			break;
		case BPMF:
			table = "bpmf";
			break;
		default:
			return;
		}

		Cursor csr = mDic.rawQuery("Select val from " + table
				+ " where key =\"" + mBuffer.toString() + "\"", null);

		if (csr.getCount() == 1) {
			csr.moveToFirst();
			insertWord(csr.getString(csr.getColumnIndex("val")));
			clearBuffer();
			csr.close();
			return;
		}

		if (csr.getCount() == 0) {
			clearBuffer();
			ezcin.setBufferText(ctx.getString(R.string.nomatch));
			csr.close();
			return;
		}

		mCurrentPage = 0;
		mTotalPages = csr.getCount() / CANDIDATES_PER_PAGE;
		if (CANDIDATES_PER_PAGE * mTotalPages < csr.getCount()) {
			mTotalPages++;
		}

		mCandidates = new ArrayList<String>();

		int count = csr.getCount();
		int colIdx = csr.getColumnIndex("val");
		csr.moveToNext();
		for (int i = 0; i < count; i++) {
			String ca = csr.getString(colIdx);
			mCandidates.add(ca);
			csr.moveToNext();
		}
		csr.close();

		renderCandidates();
	}

	private void renderCandidates() {
		ezcin.setBufferText(mDispBuffer + "  " + (mCurrentPage + 1) + "/"
				+ mTotalPages);

		int totallength = 0;
		for (int i = 0; i < CANDIDATES_PER_PAGE
				&& (i + mCurrentPage * CANDIDATES_PER_PAGE) < mCandidates
						.size(); i++) {
			String candidate = mCandidates.get(i + mCurrentPage
					* CANDIDATES_PER_PAGE);
			mCandidateButtons.get(i).setText(candidate);
			totallength += candidate.length();
		}

		if (totallength < CANDIDATES_PER_PAGE)
			totallength = CANDIDATES_PER_PAGE;
		for (int i = 0; i < CANDIDATES_PER_PAGE
				&& (i + mCurrentPage * CANDIDATES_PER_PAGE) < mCandidates
						.size(); i++) {
			mCandidateButtons.get(i).setTextSize(
					CANDIDATES_DEFAULT_FONT_SIZE * CANDIDATES_PER_PAGE
							/ totallength);
			mCandidateButtons.get(i).setVisibility(View.VISIBLE);
		}

	}

	private void insertWord(String word) {
		int target = ezcin.gText.getSelectionStart();
		CharSequence left = ezcin.gText.getText().subSequence(0, target);
		CharSequence right = ezcin.gText.getText().subSequence(target,
				ezcin.gText.length());
		ezcin.gText.setText(left.toString() + word + right.toString());
		ezcin.gText.setSelection(target + word.length());
	}

	private void appendBuffer(String translate, HashMap<String, String> symbol,
			int index) {
		String keyraw = "";
		keyraw = translate.substring(index, index + 1);
		mBuffer.append(keyraw);
		mDispBuffer.append(symbol.get(keyraw));
		ezcin.setBufferText(mDispBuffer.toString());
	}

	private void clearBuffer() {
		mBuffer.delete(0, mBuffer.length());
		mDispBuffer.delete(0, mDispBuffer.length());
		ezcin.setBufferText("");
	}

	private void hideSelectionButtons() {
		for (Button b : mCandidateButtons) {
			b.setVisibility(View.GONE);
		}
	}

	private void changeKeyboard(int index) {
		switch (index) {
		case 0:
			ezcin.gInstance.updateKeyboard("EZ");
			break;
		case 1:
			ezcin.gInstance.updateKeyboard("BPMF");
			break;
		case 2:
			ezcin.gInstance.updateKeyboard("ENG");
			break;
		case 3:
			ezcin.gInstance.updateKeyboard("SYM");
			break;
		}
		ezcin.setBufferText("");
	}

	public void closeDatabase() {
		if (mDic != null) {
			mDic.close();
		}
	}

	private boolean isChoosingCandidates() {
		if (mCandidateButtons.size() > 0) {
			if (mCandidateButtons.get(0).getVisibility() == View.VISIBLE) {
				return true;
			}
		}
		return false;
	}

}
